//
// Created by 成飞 on 2024/2/6.
//

#ifndef ORDERKV_LOCK_HPP
#define ORDERKV_LOCK_HPP
#include <atomic>
#include <thread>
#include <condition_variable>

class PreferenceLock {
private:
    std::atomic<bool> locked = false;
    std::atomic<std::thread::id> owner_thread_id = std::thread::id();

public:
    void lock() {
        std::thread::id this_thread_id = std::this_thread::get_id();
        if (!locked.exchange(true)) {
            owner_thread_id = this_thread_id;
        } else if (owner_thread_id != this_thread_id) {
            while (locked.load()) {
                // 自旋等待锁释放
            }
            owner_thread_id = this_thread_id;
        }
    }

    void unlock() {
        std::thread::id this_thread_id = std::this_thread::get_id();
        if (owner_thread_id == this_thread_id) {
            locked.store(false);
        }
    }
};

class SpinLock {
private:
    std::atomic_flag flag = ATOMIC_FLAG_INIT;

public:
    void lock() {
        while (flag.test_and_set(std::memory_order_acquire)) {
            // 自旋等待，直到锁被释放
        }
    }

    void unlock() {
        flag.clear(std::memory_order_release);
    }
};


class RWLock {
private:
    std::mutex mtx;
    std::condition_variable read_cv;
    std::condition_variable write_cv;
    int readers;
    bool writing;

public:
    RWLock() : readers(0), writing(false) {}

    void lockRead() {
        std::unique_lock<std::mutex> lock(mtx);
        while (writing) {
            read_cv.wait(lock);
        }
        ++readers;
    }

    void unlockRead() {
        std::unique_lock<std::mutex> lock(mtx);
        --readers;
        if (readers == 0) {
            write_cv.notify_one();
        }
    }

    void lockWrite() {
        std::unique_lock<std::mutex> lock(mtx);
        while (writing || readers > 0) {
            write_cv.wait(lock);
        }
        writing = true;
    }

    void unlockWrite() {
        std::unique_lock<std::mutex> lock(mtx);
        writing = false;
        read_cv.notify_all();
        write_cv.notify_one();
    }
};

#endif //ORDERKV_LOCK_HPP
